home *** CD-ROM | disk | FTP | other *** search
- /* build in E.
-
- TODO: - cyclic structure check (part)
- - (amigados?) constants (part)
-
- */
-
- OPT OSVERSION=37
-
- MODULE 'tools/file', 'dos/dosextens', 'dos/dos'
-
- /*
- symbol=object
- object: dep1 dep2 ....
- act1
- act2
-
- $(symbol): $(symbol)bla ....
- act1
- ...
- */
-
- /*
- history:
-
- (Version 0.8 by Rob and Wouter)
-
- When Who What
- 23.07.97 Glauschwuffel - Added symbolic constants. Constants are allowed everywhere
- 26.07.97 Glauschwuffel - Removed bug in constants: The part after the last constant
- wouldn't be copied. $(test): $(test).e crashed in cyclic
- dependancy. :(
- - Used source that Jason mailed me to get right order of actions.
- - Minor modification in traverse(): "circ" is raised when object
- and a dependancy have the same name.
- - Added version facility :)
- - local constant $(target) is now available in actions
- - Added QUIET arg
- 27.07.97 Glauschwuffel - Changed QUIET to VERBOSE since quiet was default for v3.1
- (between Glauschwuffel - Used EBuild with new oomodules/ objects. *Very* stable, no errrors
- at all. I tend to say it's error-free <g>)
- 09.08.97 Glauschwuffel - Actions of a target are now collected in a script again.
- EBuild now acts as described in the Ev3.2 doc (except of the
- modified $target). Bumped version to 0.9.
- 10.08.97 Glauschwuffel - Added script variable $target for reasons of consistency. Now
- $(target) and $target are possible.
- Discovered a potential bug: if build is called without a target and
- the first target in the buildfile is not a filename (e.g. a symbolic
- target like `all' or `clean') the actions for this target are
- executed anyway (0.8 does this, too).
- 05.09.97 Glauschwuffel - BUG: the temporary script in T: won't be closed on exceptions
- Fixed.
- 13.09.97 Glauschwuffel - ADD: commandline option CONSTANTS. Lists the constants before executing
- anything. Modified `dumpC()' for this.
- 12.10.97 Glauschwuffel - BUG: EBuild would cause an enforcer hit when no dependent objects are
- specified (as with symbolic targets like 'clean'). target was only set
- when there were dependencies, moved the statement two lines higher.
- Fixed. Bumped version. Thanks to Nuno for the report.
- */
-
- OBJECT object
- next:PTR TO object
- name:PTR TO CHAR
- firstdep:PTR TO dependancy
- firstaction:PTR TO action
- child
- lastaction:PTR TO action
- ENDOBJECT
-
- OBJECT dependancy
- next:PTR TO dependancy
- object:PTR TO object
- ENDOBJECT
-
- OBJECT action
- next:PTR TO action
- comstring:PTR TO CHAR
- ENDOBJECT
-
- OBJECT arg
- target,buildfile,force,verbose,nohead,constants
- ENDOBJECT
-
- OBJECT constant
- next:PTR TO constant
- name:PTR TO CHAR
- subst:PTR TO CHAR
- ENDOBJECT
-
- DEF curline=0, curstring, uptodate=TRUE, args:PTR TO arg,
- constants:PTR TO constant, -> global list of constants in reverse order
- target:PTR TO CHAR -> holds name of current target
-
- PROC main() HANDLE
- DEF m,l,buildfile[200]:STRING,rdargs=NIL
- NEW args
- IF (rdargs:=ReadArgs('TARGET,FROM/K,FORCE/S,VERBOSE/S,NOHEAD/S,CONSTANTS/S',args,NIL))=NIL THEN Raise("barg")
- IF args.buildfile THEN StrCopy(buildfile,args.buildfile)
- StrAdd(buildfile,'.build')
- IF (args.nohead = 0) -> be VERY quiet
- PrintF({versionString})
- PrintF(' (processing "\s")\n', buildfile)
- ENDIF
- m,l:=readfile(buildfile)
- buildtree(parse(stringsinfile(m,l,countstrings(m,l))))
- IF uptodate THEN PrintF('All files are up to date.\n')
- Raise()
- EXCEPT
- IF rdargs THEN FreeArgs(rdargs)
- IF exception=0 THEN RETURN
- PrintF('Error: ')
- SELECT exception
- CASE "OPEN"
- PrintF('couldn''t open "\s".\n',exceptioninfo)
- CASE "MEM"
- PrintF('not enough memory.\n')
- CASE "IN"
- PrintF('couldn''t read file.\n')
- CASE "nobj"
- PrintF('action without object.\n')
- CASE "fexp"
- PrintF('filename expected.\n')
- CASE "dexp"
- PrintF('":" or "=" expected.\n')
- CASE "empt"
- PrintF('nothing to build.\n')
- CASE "circ"
- PrintF('circular dependancies at file "\s".\n', exceptioninfo)
- CASE "bada"
- PrintF('action failed to build "\s".\n',exceptioninfo)
- CASE "badd"
- PrintF('dependancy "\s" not available.\n',exceptioninfo)
- CASE "derr"
- PrintF('child process failed.\n')
- CASE "ntar"
- PrintF('no such target: "\s".\n',args.target)
- CASE "ndep"
- PrintF('no dependancies for object "\s".\n',exceptioninfo)
- CASE "clos"
- PrintF('missing closing brace: "\s".\n',exceptioninfo)
- CASE "cons"
- PrintF('unknown constant: "\s".\n',exceptioninfo)
- CASE "barg"
- PrintFault(IoErr(),NIL)
- CASE "scrp"
- PrintF ('unable to create temporary script.\n')
- DEFAULT
- PrintF('burp.\n')
- ENDSELECT
- IF curline THEN PrintF('at line: (\d) "\s"\n',curline,curstring)
- IF exception THEN PrintF('Build terminated\n')
- RETURN 10
- ENDPROC
-
- PROC parse(list:PTR TO LONG)
- DEF l=NIL:PTR TO object, s, c, i, t, const=NIL:PTR TO constant,str:PTR TO CHAR
- FOR curline:=0 TO ListLen(list)-1
- s:=list[curline]
- curstring:=s
- c:=s[]
- IF (c<>"#") AND (c<>"\0") -> ignore?
- IF (c=" ") OR (c="\t") -> action
- s:=eatwhite(s)
- IF s[]
- IF l=NIL THEN Raise("nobj")
- -> was: l.firstaction:=NEW [l.firstaction,s]:action
- -> replaced by the following IF (Rob through Glauschwuffel)
- IF l.lastaction
- l.lastaction.next:=NEW [NIL,s]:action
- l.lastaction:=l.lastaction.next
- ELSE
- l.firstaction:=NEW [NIL,s]:action
- l.lastaction:=l.firstaction
- ENDIF
- ENDIF
- ELSE -> object rule or constant
- i:=s
- s:=eatname(s)
- IF s=i THEN Raise("fexp")
- t:=s
-
- IF (s[]<>":") AND (s[]<>"=") THEN Raise("dexp")
- IF s[]=":"
-
- -> check object rule for use of constants
- str:=String(1024) -> dyn. alloc., free if no constants
- IF str=NIL THEN Raise("MEM")
- /* IF (substituteConstants (i, str)<>0) ->update vars if there were constants
- i := str; s:=eatname(str) -> these were copied from above
- IF s=i THEN Raise("fexp")
- t:=s
- ELSE
- Dispose(str)
- ENDIF
- */
- substituteConstants (i, str)
- i := str; s:=eatname(str)
- IF s=i THEN Raise("fexp")
- t:=s
-
-
- t[]:="\0"
- s++
- s:=eatwhite(s)
- l:=NEW [l,i,NIL,NIL,0]:object
- s:=eatwhite(s)
- IF s[]<>"\0"
- REPEAT
- i:=s
- s:=eatname(s)
- t:=s
- IF t=i THEN Raise("fexp")
- s:=eatwhite(s)
- t[]:="\0"
- l.firstdep:=NEW [l.firstdep,i]:dependancy
- UNTIL s[]="\0"
- ENDIF
- ELSE -> we have a constant
- s++
- s:=eatwhite(s)
- t[]:="\0" -> terminate name
- const:=NEW[const,i,s]:constant
- constants:=const -> have to do it here so consts in rules are recognized
- ENDIF
- ENDIF
- ENDIF
- ENDFOR
- curline:=0
- IF args.constants THEN dumpC()
- IF l=NIL THEN Raise("empt")
- ENDPROC l
-
-
- PROC eatwhite(s)
- WHILE (s[]=" ") OR (s[]="\t") DO s++
- ENDPROC s
-
- PROC eatname(s)
- WHILE (s[]<>" ") AND (s[]<>"\t") AND (s[]<>"\0") AND (s[]<>":") AND (s[]<>"=") DO s++
- ENDPROC s
-
- /* obsolete
- PROC execute(c)
- DEF s[1024]:STRING
- uptodate:=FALSE
- substituteConstants (c, s)
- IF args.verbose THEN PrintF('\t\s\n', s)
- -> PrintF('\t\s\n',IF substituteConstants (c, s) THEN s ELSE c)
- IF Execute(s,NIL,stdout)=NIL THEN Raise("derr")
- ENDPROC */
-
- PROC filetime(name:PTR TO CHAR)
- DEF l:PTR TO filelock, fib:fileinfoblock, date:PTR TO datestamp
- IF l:=Lock(name,ACTION_READ)
- IF Examine(l,fib)
- date:=fib.datestamp
- IF fib.direntrytype<0
- UnLock(l)
- RETURN date.days, Shl(date.minute,12)+date.tick
- ENDIF
- ENDIF
- UnLock(l)
- ENDIF
- ENDPROC -1
-
- PROC timelater(day1,tick1,day2,tick2)
- IF day1>day2
- RETURN TRUE
- ELSEIF day1=day2
- RETURN tick1>tick2
- ENDIF
- ENDPROC FALSE
-
- /*----------------rob's-stuff-------------------*/
-
- PROC buildtree(list:PTR TO object) -> returns root of tree
- DEF dep:PTR TO dependancy,
- obj:PTR TO object
-
- obj:=list
- WHILE obj -> traverse objects
- dep:=obj.firstdep
- WHILE dep -> traverse dependencies
- dep.object:=findobject(dep.object,list)
- dep:=dep.next
- ENDWHILE
- obj:=obj.next
- ENDWHILE
-
- -> CHECK CYCLES!!!
-
- obj:=list
- IF args.target
- WHILE obj
- IF StrCmp(args.target,obj.name) THEN JUMP out
- obj:=obj.next
- ENDWHILE
- Raise("ntar")
- out:
- ELSE
- IF obj THEN WHILE obj.next DO obj:=obj.next
- ENDIF
- traverse(obj)
- ENDPROC
-
-
- -> find object in list of objects by name
- PROC findobject(name:PTR TO CHAR,list:PTR TO object)
- WHILE list
- IF StrCmp(name,list.name)
- -> remove object from root list
- list.child:=TRUE;
- RETURN list
- ENDIF
- list:=list.next
- ENDWHILE
- ENDPROC NEW [NIL,name,NIL,NIL]:object
-
- -> child-first traversal of dependancy tree
- PROC traverse(obj:PTR TO object) -> executes actions in tree
- DEF dep:PTR TO dependancy,maxtime1=0,maxtime2=0,time1,time2,action:PTR TO action
-
- IF obj.firstdep OR obj.firstaction -> object with dependancies/actions
- -> traverse children and get maximum timestamp
- dep:=obj.firstdep
- WHILE dep
- IF OstrCmp (dep.object.name, obj.name) = 0 THEN Throw("circ",obj.name) -> cyclic check by Glauschwuffel
- target := obj.name
- time1,time2:=traverse(dep.object)
- IF timelater(time1,time2,maxtime1,maxtime2)
- maxtime1:=time1
- maxtime2:=time2
- ENDIF
- dep:=dep.next
- ENDWHILE
- time1,time2:=filetime (obj.name)
- IF time1<0 OR timelater(maxtime1,maxtime2,time1,time2) OR args.force
- -> dependancy file(s) more recent: build object
- -> execute actions
- action:=obj.firstaction
-
- buildAndExecuteScript (action)
-
- time1,time2:=filetime(obj.name)
- IF (time1<0) AND (obj.child=TRUE) THEN Throw("bada",obj.name)
- ENDIF
- RETURN time1,time2
- ENDIF
- -> object requires no action: return timestamp
- time1,time2:=filetime(obj.name);
- IF time1<0 THEN Throw("badd",obj.name)
- ENDPROC time1,time2
-
- /* - glauschwuffel's stuff --- */
-
-
- PROC dumpC()
- DEF co:PTR TO constant
- co:=constants
- WriteF ('Constants are:\n')
- WHILE co
- WriteF('\t<\s> with <\s>.\n', co.name, co.subst)
- co:=co.next
- ENDWHILE
- ENDPROC
-
- PROC substituteConstants(c:PTR TO CHAR, s:PTR TO CHAR)
- -> search c for constants and substitute them
- DEF dollar, bclose=-1,sub=NIL
- REPEAT
- bclose++
- dollar := InStr (c,'$(',bclose)
- IF (dollar<>-1) -> found it?
- StrAdd (s, c+bclose, dollar-bclose)
- bclose := InStr (c,')',dollar+2)
- IF bclose=-1 THEN Throw("clos",c)
- sub := findConstant(c,dollar+2,bclose-1)
- IF sub=NIL THEN Throw("cons",c+dollar)
- StrAdd (s,sub)
- ELSE -> copy rest of the line to buffer
- StrAdd (s, c+bclose)
- ENDIF
- UNTIL (dollar=-1) OR (bclose=-1)
- RETURN sub -> did we substitute something at all?
- ENDPROC
-
- PROC findConstant(c,start,end)
- -> find constant of given position in list
- -> add 27.07.97: returns global target on target
- DEF co:PTR TO constant
- IF OstrCmp('target',c+start,end-start+1)=0 THEN RETURN target
- co:=constants
- WHILE co
- EXIT (OstrCmp(co.name,c+start,end-start+1)=0)
- co:=co.next
- ENDWHILE
- RETURN IF co THEN co.subst ELSE NIL
- ENDPROC
-
- PROC buildAndExecuteScript (action:PTR TO action) HANDLE
- DEF s[1024]:STRING,
- handle
-
- handle := Open ('T:Ebuild_actions', MODE_NEWFILE) -> open script file
- IF (handle = NIL) THEN Raise ("scrp")
-
- /* create script variable TARGET */
- StrCopy (s, 'Set target ')
- StrAdd (s, target)
- StrAdd (s, '\n') -> add newline
-
- Write (handle, s, StrLen (s))
- IF args.verbose THEN PrintF('\t\s', s)
-
- WHILE action
- uptodate:=FALSE
- SetStr (s, 0) -> "delete" the string of the last action
- substituteConstants (action.comstring, s) -> expand action
- StrAdd (s, '\n') -> add newline
- IF args.verbose THEN PrintF('\t\s', s)
- Write (handle, s, StrLen (s))
- action:=action.next
- ENDWHILE
-
- Close (handle)
- IF Execute('Execute T:Ebuild_actions', NIL, stdout)=NIL THEN Raise("derr")
- DeleteFile ('T:EBuild_actions')
-
- EXCEPT
- IF handle THEN Close(handle)
- ReThrow()
- ENDPROC
-
-
- versionTag: CHAR 0,'$VER:'
- versionString: CHAR 'EBuild 0.92 (12.10.97) ©1997 Rob, Wouter and Glauschwuffel',0
-
-